-- Lua Battle System - 轻量级测试框架

local TestFramework = {}
local Logger = require("src.utils.logger")

-- 测试状态统计
local stats = {
    total_tests = 0,
    passed_tests = 0,
    failed_tests = 0,
    errors = 0,
    current_suite = nil
}

-- 当前测试套件
local current_test_suite = nil

-- 断言函数
local Assert = {}

-- 基础断言：值相等
function Assert.equals(expected, actual, message)
    stats.total_tests = stats.total_tests + 1

    if expected ~= actual then
        local error_msg = message or string.format("Expected %s, but got %s", tostring(expected), tostring(actual))
        stats.failed_tests = stats.failed_tests + 1
        print(string.format("❌ FAIL: %s - %s", current_test_suite or "Unknown", error_msg))
        return false
    else
        stats.passed_tests = stats.passed_tests + 1
        print(string.format("✅ PASS: %s - %s", current_test_suite or "Unknown", message or "Value equals"))
        return true
    end
end

-- 断言：值不相等
function Assert.not_equals(expected, actual, message)
    stats.total_tests = stats.total_tests + 1

    if expected == actual then
        local error_msg = message or string.format("Expected not %s, but got %s", tostring(expected), tostring(actual))
        stats.failed_tests = stats.failed_tests + 1
        print(string.format("❌ FAIL: %s - %s", current_test_suite or "Unknown", error_msg))
        return false
    else
        stats.passed_tests = stats.passed_tests + 1
        print(string.format("✅ PASS: %s - %s", current_test_suite or "Unknown", message or "Value not equals"))
        return true
    end
end

-- 断言：值为真
function Assert.is_true(value, message)
    return Assert.equals(true, value, message or "Expected true")
end

-- 断言：值为假
function Assert.is_false(value, message)
    return Assert.equals(false, value, message or "Expected false")
end

-- 断言：值为nil
function Assert.is_nil(value, message)
    return Assert.equals(nil, value, message or "Expected nil")
end

-- 断言：值不为nil
function Assert.is_not_nil(value, message)
    return Assert.not_equals(nil, value, message or "Expected not nil")
end

-- 断言：类型匹配
function Assert.is_type(expected_type, value, message)
    local actual_type = type(value)
    stats.total_tests = stats.total_tests + 1

    if expected_type ~= actual_type then
        local error_msg = message or string.format("Expected type %s, but got %s", expected_type, actual_type)
        stats.failed_tests = stats.failed_tests + 1
        print(string.format("❌ FAIL: %s - %s", current_test_suite or "Unknown", error_msg))
        return false
    else
        stats.passed_tests = stats.passed_tests + 1
        print(string.format("✅ PASS: %s - %s", current_test_suite or "Unknown", message or "Type matches"))
        return true
    end
end

-- 断言：表包含指定键
function Assert.table_contains_key(table, key, message)
    stats.total_tests = stats.total_tests + 1

    if type(table) ~= "table" then
        local error_msg = message or string.format("Expected table, but got %s", type(table))
        stats.failed_tests = stats.failed_tests + 1
        print(string.format("❌ FAIL: %s - %s", current_test_suite or "Unknown", error_msg))
        return false
    end

    if table[key] == nil then
        local error_msg = message or string.format("Table does not contain key: %s", tostring(key))
        stats.failed_tests = stats.failed_tests + 1
        print(string.format("❌ FAIL: %s - %s", current_test_suite or "Unknown", error_msg))
        return false
    else
        stats.passed_tests = stats.passed_tests + 1
        print(string.format("✅ PASS: %s - %s", current_test_suite or "Unknown", message or "Table contains key"))
        return true
    end
end

-- 断言：函数抛出错误
function Assert.throws(func, expected_error_msg, message)
    stats.total_tests = stats.total_tests + 1

    if type(func) ~= "function" then
        local error_msg = message or "Expected function as first argument"
        stats.failed_tests = stats.failed_tests + 1
        print(string.format("❌ FAIL: %s - %s", current_test_suite or "Unknown", error_msg))
        return false
    end

    local status, error = pcall(func)
    if status then
        local error_msg = message or "Expected function to throw an error, but it didn't"
        stats.failed_tests = stats.failed_tests + 1
        print(string.format("❌ FAIL: %s - %s", current_test_suite or "Unknown", error_msg))
        return false
    else
        if expected_error_msg and not string.find(tostring(error), expected_error_msg, 1, true) then
            local error_msg = message or string.format("Expected error message containing '%s', but got '%s'", expected_error_msg, tostring(error))
            stats.failed_tests = stats.failed_tests + 1
            print(string.format("❌ FAIL: %s - %s", current_test_suite or "Unknown", error_msg))
            return false
        else
            stats.passed_tests = stats.passed_tests + 1
            print(string.format("✅ PASS: %s - %s", current_test_suite or "Unknown", message or "Function throws expected error"))
            return true
        end
    end
end

-- 测试套件类
local TestSuite = {}
TestSuite.__index = TestSuite

function TestSuite.new(name)
    local suite = {
        name = name,
        tests = {},
        setup_func = nil,
        teardown_func = nil
    }
    setmetatable(suite, TestSuite)
    return suite
end

function TestSuite:add_test(test_name, test_func)
    table.insert(self.tests, {
        name = test_name,
        func = test_func
    })
end

function TestSuite:setup(setup_func)
    self.setup_func = setup_func
end

function TestSuite:teardown(teardown_func)
    self.teardown_func = teardown_func
end

function TestSuite:run()
    current_test_suite = self.name
    print(string.format("\n📋 Running test suite: %s", self.name))
    print(string.rep("=", 50))

    local suite_passed = 0
    local suite_failed = 0

    for _, test in ipairs(self.tests) do
        print(string.format("\n🔍 Test: %s", test.name))

        -- 执行setup
        if self.setup_func then
            local status, error = pcall(self.setup_func)
            if not status then
                stats.errors = stats.errors + 1
                print(string.format("💥 ERROR in setup: %s", tostring(error)))
                suite_failed = suite_failed + 1
                goto continue
            end
        end

        -- 执行测试
        local status, error = pcall(test.func)
        if not status then
            stats.errors = stats.errors + 1
            stats.failed_tests = stats.failed_tests + 1
            stats.total_tests = stats.total_tests + 1
            print(string.format("💥 ERROR: %s", tostring(error)))
            suite_failed = suite_failed + 1
        end

        -- 执行teardown
        if self.teardown_func then
            local status, error = pcall(self.teardown_func)
            if not status then
                stats.errors = stats.errors + 1
                print(string.format("💥 ERROR in teardown: %s", tostring(error)))
            end
        end

        ::continue::
    end

    print(string.format("\n📊 Suite %s completed", self.name))
    current_test_suite = nil
end

-- 框架主函数
TestFramework.Assert = Assert
TestFramework.TestSuite = TestSuite

-- 创建测试套件
function TestFramework.create_suite(name)
    return TestSuite.new(name)
end

-- 重置统计信息
function TestFramework.reset_stats()
    stats = {
        total_tests = 0,
        passed_tests = 0,
        failed_tests = 0,
        errors = 0,
        current_suite = nil
    }
end

-- 获取统计信息
function TestFramework.get_stats()
    return {
        total = stats.total_tests,
        passed = stats.passed_tests,
        failed = stats.failed_tests,
        errors = stats.errors,
        success_rate = stats.total_tests > 0 and (stats.passed_tests / stats.total_tests * 100) or 0
    }
end

-- 打印测试报告
function TestFramework.print_report()
    local stats_data = TestFramework.get_stats()
    print(string.rep("=", 60))
    print("📋 TEST REPORT")
    print(string.rep("=", 60))
    print(string.format("Total Tests: %d", stats_data.total))
    print(string.format("Passed: %d ✅", stats_data.passed))
    print(string.format("Failed: %d ❌", stats_data.failed))
    print(string.format("Errors: %d 💥", stats_data.errors))
    print(string.format("Success Rate: %.2f%%", stats_data.success_rate))
    print(string.rep("=", 60))

    if stats_data.failed == 0 and stats_data.errors == 0 then
        print("🎉 All tests passed!")
        return true
    else
        print("⚠️  Some tests failed or had errors!")
        return false
    end
end

-- 运行所有测试套件
function TestFramework.run_all_suites(suites)
    print("🚀 Starting test runner...")
    print(string.rep("=", 60))

    TestFramework.reset_stats()

    for _, suite in ipairs(suites) do
        suite:run()
    end

    return TestFramework.print_report()
end

-- 便捷函数：运行单个测试文件
function TestFramework.run_test_file(test_file_path)
    print(string.format("📂 Loading test file: %s", test_file_path))

    local status, test_module = pcall(dofile, test_file_path)
    if not status then
        print(string.format("💥 Failed to load test file: %s", tostring(test_module)))
        return false
    end

    if type(test_module) == "table" and test_module.run_tests then
        return test_module.run_tests()
    else
        print("⚠️  Test file does not export a run_tests function")
        return false
    end
end

-- 查找并运行所有测试
function TestFramework.run_all_tests(test_dir)
    test_dir = test_dir or "tests"

    print(string.format("🔍 Discovering tests in: %s", test_dir))

    -- 这里可以实现自动发现测试文件的逻辑
    -- 为了简化，暂时只运行指定的测试文件
    print("ℹ️  Auto-discovery not implemented yet. Please specify test files manually.")

    return false
end

return TestFramework